#include "pch.h"
#include "RenderToTexture.h"
#include "ResourceManager.h"
#include "ScriptPlugin.h"
#include "RendererEngine.h"

namespace mini
{
	CRenderToTexture::CRenderToTexture(INT32 width, INT32 height)
	: mWidth(width)
	, mHeight(height)
	{

	}

	CRenderToTexture::~CRenderToTexture()
	{
		SafeRelease(mpDepthStencilBuffer);
		SafeRelease(mpDepthStencilView);
		SafeRelease(mpTexuture);
	}

	bool CRenderToTexture::createBuffer(UINT32 format, UINT bindInfo, UINT32 nTextureFormat)
	{
		CDevice* pDevice = CRendererEngine::getSinglePtr()->getDevice();
//		mpDeviceContext = CRendererEngine::getSinglePtr()->findRenderer(FrontRenderer)->getDeviceContext();

		D3D11_TEXTURE2D_DESC depthBufferDesc;
		// Initialize the description of the depth buffer.
		ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));

		// Set up the description of the depth buffer.
		depthBufferDesc.Width = mWidth;
		depthBufferDesc.Height = mHeight;
		depthBufferDesc.MipLevels = 1;
		depthBufferDesc.ArraySize = 1;
		depthBufferDesc.Format =(DXGI_FORMAT)format;// DXGI_FORMAT_D24_UNORM_S8_UINT;
		depthBufferDesc.SampleDesc.Count = 1;
		depthBufferDesc.SampleDesc.Quality = 0;
		depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
		depthBufferDesc.BindFlags = bindInfo;// D3D11_BIND_DEPTH_STENCIL;
		depthBufferDesc.CPUAccessFlags = 0;
		depthBufferDesc.MiscFlags = 0;

		// Create the texture for the depth buffer using the filled out description.
		HRESULT result = pDevice->getDevice()->CreateTexture2D(&depthBufferDesc, NULL, &mpDepthStencilBuffer);
		if (FAILED(result))
		{
			return false;
		}

		D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
		// Initialize the depth stencil view.
		ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

		// Set up the depth stencil view description.
		depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
		depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
		depthStencilViewDesc.Texture2D.MipSlice = 0;

		// Create the depth stencil view.
		result = pDevice->getDevice()->CreateDepthStencilView(mpDepthStencilBuffer, &depthStencilViewDesc, &mpDepthStencilView);
		if (FAILED(result))
		{
			return false;
		}
		mpTexuture = new (std::nothrow) CTexture();

		if (nullptr != mpTexuture)
		{
			mpTexuture->initialiseRenderTexture(mWidth, mHeight, nTextureFormat);
			// Setup the viewport for rendering.
			m_viewport.Width = (float)mWidth;
			m_viewport.Height = (float)mHeight;
			m_viewport.MinDepth = 0.0f;
			m_viewport.MaxDepth = 1.0f;
			m_viewport.TopLeftX = 0.0f;
			m_viewport.TopLeftY = 0.0f;

			// Setup the projection matrix.
			D3DXMatrixPerspectiveFovLH(&mProjectMatrix, ((float)D3DX_PI / 4.0f), ((float)mWidth / (float)mHeight), 1, 1000);

			// Create an orthographic projection matrix for 2D rendering.
			D3DXMatrixOrthoLH(&mOrthoMatrix, (float)mWidth, (float)mHeight, 1, 1000);

			return true;
		}
		else
		{
			return false;
		}
	}

	void CRenderToTexture::beginRender(const CPoint4F& clearColor, DeviceContext* pConetext)
	{
		if (nullptr != pConetext)
		{
			if (nullptr != mpTexuture)
			{
				pConetext->OMSetRenderTargets(1, &mpTexuture->mpRenderTargetView, mpDepthStencilView);
				mpTexuture->clearRenderTargetView(clearColor);
				if (nullptr != mpDepthStencilBuffer)
				{
					pConetext->ClearDepthStencilView(mpDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
				}
			}
		}
	}

	void CRenderToTexture::endRender(DeviceContext* pConetext)
	{
		CDevice* pDevice = CRendererEngine::getSinglePtr()->getDevice();
		pDevice->recoverBackBuffer(pConetext);
		pDevice->recoverViewport(pConetext);
	}


	CTexture* CRenderToTexture::getRenderTexture()
	{
		return mpTexuture;
	}

	bool CRenderToTexture::saveToFile(const std::string szFile, UINT32 nFormat)
	{
		if (nullptr != mpTexuture)
		{
			return mpTexuture->saveToFile(szFile, nFormat);
		}
		else
		{
			return false;
		}
	}



	void CRenderToTexture::setSampler(ID3D11SamplerState* pSampler)
	{
		if (nullptr != mpTexuture)
		{
			mpTexuture->setSampleState(pSampler);
		}
	}

	void CRenderToTexture::createViewport()
	{
		m_viewport.Width = (float)mWidth;
		m_viewport.Height = (float)mHeight;
		m_viewport.MinDepth = 0.0f;
		m_viewport.MaxDepth = 1.0f;
		m_viewport.TopLeftX = 0.0f;
		m_viewport.TopLeftY = 0.0f;
	}

	void CRenderToTexture::applyViewport(DeviceContext* pConetext, int nIndex)
	{
		pConetext->RSSetViewports(nIndex, &m_viewport);
	}

	CMatrix& CRenderToTexture::getProjectMatrix()
	{
		return mProjectMatrix;
	}

	CMatrix& CRenderToTexture::getOrthoMatrix()
	{
		return mOrthoMatrix;
	}

	ID3D11RenderTargetView* CRenderToTexture::getRenderTargetView()
	{
		if (nullptr != mpTexuture)
		{
			return mpTexuture->mpRenderTargetView;
		}
		else
		{
			return nullptr;
		}
	}

}
